#include "face_api.h"
#include "face_app.h"

#if (_SAFETY_MODULE_TYPE_ == _FACE_SAFETY_MODULE_) && (_SAFETY_VERIFYFUNCTION_ENABLE_)

/**
 * @brief 获取待注册的方向
 *
 * @param NowDirection - 当前方向
 * @return uint8_t     - 待注册的方向
 */
static uint8_t FaceGetLocalRegisterDirection(uint8_t NowDirection);

/**
 * @brief 更新录入方向
 *
 * @param Direction - 待注册的方向
 */
static void FaceUpdateEnrollmentDirection(uint8_t Direction);

static FaceBitStatus_t FaceBitStatus = {0};

static uint8_t FaceGetLocalRegisterDirection(uint8_t NowDirection)
{
  switch (NowDirection)
  {
  case FACE_DIRECTION_MIDDLE:
    return FACE_DIRECTION_UP;

  case FACE_DIRECTION_UP:
    return FACE_DIRECTION_DOWN;

  case FACE_DIRECTION_DOWN:
    return FACE_DIRECTION_LEFT;

  case FACE_DIRECTION_LEFT:
    return FACE_DIRECTION_RIGHT;

  default:
    return FACE_DIRECTION_MIDDLE;
  }
}

static void FaceUpdateEnrollmentDirection(uint8_t Direction)
{
  switch (Direction)
  {
  case FACE_DIRECTION_UP:
    FaceUpdateRegistrationDirectionToUp();
    break;

  case FACE_DIRECTION_DOWN:
    FaceUpdateRegistrationDirectionToDown();
    break;

  case FACE_DIRECTION_LEFT:
    FaceUpdateRegistrationDirectionToLeft();
    break;

  case FACE_DIRECTION_RIGHT:
    FaceUpdateRegistrationDirectionToRight();
    break;

  default:
    FaceUpdateTheEnrollmentDirectionToFront();
    break;
  }
}

uint8_t FaceGetTheNumberOfRegisteredUsers(void)
{
  return FaceBitStatus.HardwareAttribute.NumberOfUser;
}

void FaceGetDeviceSerialNumber(char *pSerialNumberOut)
{
  if (pSerialNumberOut != NULL)
  {
    strcpy(pSerialNumberOut, FaceBitStatus.HardwareAttribute.SerialNumber);
  }
}

void FaceGetApplicationVersion(char *pVersionOut)
{
  if (pVersionOut != NULL)
  {
    strcpy(pVersionOut, FaceBitStatus.HardwareAttribute.ApplicationVersion);
  }
}

void FaceGetAlgorithmVersion(char *pVersionOut)
{
  if (pVersionOut != NULL)
  {
    strcpy(pVersionOut, FaceBitStatus.HardwareAttribute.AlgorithmVersion);
  }
}

bool FaceBuildSelfTestMessage(uint8_t *pMessageOut, uint16_t *pSizeOut, uint32_t *pResponseTimeOut)
{
  bool BuildMessageResults = false;

  if ((pMessageOut != NULL) && (pSizeOut != NULL) && (pResponseTimeOut != NULL))
  {
    switch (FaceBitStatus.EventStatus.StepsOfSending)
    {
    case FACE_EXECUTE_FACTORY_RESET:
    {
      FaceBitStatus.EventStatus.MessageId = FACE_MESSAGE_REPLY;
      FaceBitStatus.EventStatus.CommandToSend = FACE_API_DEL_ALL_CMD;
      *pResponseTimeOut = FACE_MESSAGE_SENGING_RATED_TIME;

      BuildMessageResults = FaceBuildDeleteAllUserMessage(pMessageOut, pSizeOut);
    }
    break;

    case FACE_GET_SERIAL_NUMBER:
    {
      FaceBitStatus.EventStatus.MessageId = FACE_MESSAGE_REPLY;
      FaceBitStatus.EventStatus.CommandToSend = FACE_API_GET_SN_CMD;

      BuildMessageResults = FaceBuildGetModuleSnMessage(pMessageOut, pSizeOut);
      *pResponseTimeOut = FACE_MESSAGE_SENGING_RATED_TIME;
    }
    break;

    case FACE_GET_APPLICATION_VERSION:
    {
      FaceBitStatus.EventStatus.MessageId = FACE_MESSAGE_REPLY;
      FaceBitStatus.EventStatus.CommandToSend = FACE_API_GET_VERSION_CMD;

      BuildMessageResults = FaceBuildGetModuleVersionMessage(pMessageOut, pSizeOut);
      *pResponseTimeOut = FACE_MESSAGE_SENGING_RATED_TIME;
    }
    break;

    case FACE_GET_ALGORITHM_VERSION:
    {
      FaceBitStatus.EventStatus.MessageId = FACE_MESSAGE_REPLY;
      FaceBitStatus.EventStatus.CommandToSend = FACE_API_GET_ALGORITHM_VERSION;

      BuildMessageResults = FaceBuildGetAlgorithmVersion(pMessageOut, pSizeOut);
      *pResponseTimeOut = FACE_MESSAGE_SENGING_RATED_TIME;
    }
    break;

    case FACE_GET_NUMBER_OF_TEMPLATE:
    {
      FaceBitStatus.EventStatus.MessageId = FACE_MESSAGE_REPLY;
      FaceBitStatus.EventStatus.CommandToSend = FACE_API_GET_ALL_USER_ID_CMD;

      BuildMessageResults = FaceBuildGetAllUserIdMessage(pMessageOut, pSizeOut);
      *pResponseTimeOut = FACE_MESSAGE_SENGING_RATED_TIME;
    }
    break;

    case FACE_INTO_POWER_DOWM:
    {
      FaceBitStatus.EventStatus.MessageId = FACE_MESSAGE_REPLY;
      FaceBitStatus.EventStatus.CommandToSend = FACE_API_POWER_DOWN_CMD;

      BuildMessageResults = FaceBuildModulePowerDownMessage(pMessageOut, pSizeOut);
      *pResponseTimeOut = FACE_MESSAGE_SENGING_RATED_TIME;
    }
    break;

    default:
    {
      FaceBitStatus.EventStatus.MessageId = FACE_MESSAGE_REPLY;
      FaceBitStatus.EventStatus.CommandToSend = FACE_API_GET_STATUS_CMD;
      FaceBitStatus.EventStatus.StepsOfSending = FACE_GET_MODULE_STATUS;

      BuildMessageResults = FaceBuildGetModuleStatusMessage(pMessageOut, pSizeOut);
      *pResponseTimeOut = FACE_MESSAGE_SENGING_RATED_TIME;
    }
    break;
    }
  }

  return BuildMessageResults;
}

bool FaceBuildForcedToGotoSleepMessage(uint8_t *pMessageOut, uint16_t *pSizeOut, uint32_t *pResponseTimeOut)
{
  bool BuildMessageResults = false;

  if ((pMessageOut != NULL) && (pSizeOut != NULL) && (pResponseTimeOut != NULL))
  {
    switch (FaceBitStatus.EventStatus.StepsOfSending)
    {
    case FACE_INTO_POWER_DOWM:
    {
      FaceBitStatus.EventStatus.MessageId = FACE_MESSAGE_REPLY;
      FaceBitStatus.EventStatus.CommandToSend = FACE_API_POWER_DOWN_CMD;

      BuildMessageResults = FaceBuildModulePowerDownMessage(pMessageOut, pSizeOut);
      *pResponseTimeOut = FACE_MESSAGE_SENGING_RATED_TIME;
    }
    break;

    default:
    {
      FaceBitStatus.EventStatus.MessageId = FACE_MESSAGE_REPLY;
      FaceBitStatus.EventStatus.CommandToSend = FACE_API_RESET_CMD;
      FaceBitStatus.EventStatus.StepsOfSending = FACE_INTO_STANDBY;

      BuildMessageResults = FaceBuildSoftwareResetMessage(pMessageOut, pSizeOut);
      *pResponseTimeOut = FACE_MESSAGE_SENGING_RATED_TIME;
    }
    break;
    }
  }

  return BuildMessageResults;
}

bool FaceBuildFactorySettingMessage(uint8_t *pMessageOut, uint16_t *pSizeOut, uint32_t *pResponseTimeOut)
{
  bool BuildMessageResults = false;

  if ((pMessageOut != NULL) && (pSizeOut != NULL) && (pResponseTimeOut != NULL))
  {
    switch (FaceBitStatus.EventStatus.StepsOfSending)
    {
    case FACE_EXECUTE_FACTORY_RESET:
    {
      FaceBitStatus.EventStatus.MessageId = FACE_MESSAGE_REPLY;
      FaceBitStatus.EventStatus.CommandToSend = FACE_API_DEL_ALL_CMD;

      BuildMessageResults = FaceBuildDeleteAllUserMessage(pMessageOut, pSizeOut);
      *pResponseTimeOut = FACE_MESSAGE_SENGING_RATED_TIME;
    }
    break;

    case FACE_GET_NUMBER_OF_TEMPLATE:
    {
      FaceBitStatus.EventStatus.MessageId = FACE_MESSAGE_REPLY;
      FaceBitStatus.EventStatus.CommandToSend = FACE_API_GET_ALL_USER_ID_CMD;

      BuildMessageResults = FaceBuildGetAllUserIdMessage(pMessageOut, pSizeOut);
      *pResponseTimeOut = FACE_MESSAGE_SENGING_RATED_TIME;
    }
    break;

    case FACE_INTO_POWER_DOWM:
    {
      FaceBitStatus.EventStatus.MessageId = FACE_MESSAGE_REPLY;
      FaceBitStatus.EventStatus.CommandToSend = FACE_API_POWER_DOWN_CMD;

      BuildMessageResults = FaceBuildModulePowerDownMessage(pMessageOut, pSizeOut);
      *pResponseTimeOut = FACE_MESSAGE_SENGING_RATED_TIME;
    }
    break;

    default:
    {
      FaceBitStatus.EventStatus.MessageId = FACE_MESSAGE_REPLY;
      FaceBitStatus.EventStatus.CommandToSend = FACE_API_GET_STATUS_CMD;
      FaceBitStatus.EventStatus.StepsOfSending = FACE_GET_MODULE_STATUS;

      BuildMessageResults = FaceBuildGetModuleStatusMessage(pMessageOut, pSizeOut);
      *pResponseTimeOut = FACE_MESSAGE_SENGING_RATED_TIME;
    }
    break;
    }
  }

  return BuildMessageResults;
}

bool FaceBuildGetEigenvalueFileMessage(uint8_t *pMessageOut, uint16_t *pSizeOut, uint32_t *pResponseTimeOut)
{
  bool BuildMessageResults = false;

  if ((pMessageOut != NULL) && (pSizeOut != NULL) && (pResponseTimeOut != NULL))
  {
    switch (FaceBitStatus.EventStatus.StepsOfSending)
    {
    case FACE_GET_IMAGE_INFORMATION:
    {
      FaceBitStatus.EventStatus.MessageId = FACE_MESSAGE_REPLY;
      FaceBitStatus.EventStatus.CommandToSend = FACE_API_GET_FEATURE_INFO_CMD;

      BuildMessageResults = FaceBuildGetFeatureInformatizationMessage(pMessageOut, pSizeOut, FaceBitStatus.EventStatus.TempUserId);
      *pResponseTimeOut = FACE_MESSAGE_SENGING_RATED_TIME;
    }
    break;

    case FACE_UPLOAD_IMAGE_DATA:
    {
      FaceBitStatus.EventStatus.MessageId = FACE_MESSAGE_IMAGE;
      FaceBitStatus.EventStatus.CommandToSend = FACE_API_UPLOAD_FEATURE_CMD;

      BuildMessageResults = FaceBuildUploadFeatureDataMessage(pMessageOut, pSizeOut, FaceBitStatus.FileOperation.RequestFileSize, FaceBitStatus.FileOperation.TransmitterSize);
      *pResponseTimeOut = FACE_MESSAGE_SENGING_RATED_TIME;
    }
    break;

    case FACE_INTO_POWER_DOWM:
    {
      FaceBitStatus.EventStatus.MessageId = FACE_MESSAGE_REPLY;
      FaceBitStatus.EventStatus.CommandToSend = FACE_API_POWER_DOWN_CMD;

      BuildMessageResults = FaceBuildModulePowerDownMessage(pMessageOut, pSizeOut);
      *pResponseTimeOut = FACE_MESSAGE_SENGING_RATED_TIME;
    }
    break;

    default:
    {
      FaceBitStatus.EventStatus.MessageId = FACE_MESSAGE_REPLY;
      FaceBitStatus.EventStatus.CommandToSend = FACE_API_GET_STATUS_CMD;
      FaceBitStatus.EventStatus.StepsOfSending = FACE_GET_MODULE_STATUS;

      BuildMessageResults = FaceBuildGetModuleStatusMessage(pMessageOut, pSizeOut);
      *pResponseTimeOut = FACE_MESSAGE_SENGING_RATED_TIME;
    }
    break;
    }
  }

  return BuildMessageResults;
}

bool FaceBuildLocalRegisterUserMessage(uint8_t *pMessageOut, uint16_t *pSizeOut, uint32_t *pResponseTimeOut)
{
  bool BuildMessageResults = false;

  if ((pMessageOut != NULL) && (pSizeOut != NULL))
  {
    switch (FaceBitStatus.EventStatus.StepsOfSending)
    {
    case FACE_USER_INTERACTIVE_REGISTRATION:
    {
      uint8_t SearchTimeout = FaceGetSearchTimeout();
      FaceBitStatus.EventStatus.MessageId = FACE_MESSAGE_REPLY;
      FaceBitStatus.EventStatus.CommandToSend = FACE_API_ENROLL_ITG_CMD;
      FaceBitStatus.RegisterStatus.AdmissionDirection = FaceGetLocalRegisterDirection(FaceBitStatus.RegisterStatus.AdmissionDirection);

      BuildMessageResults = FaceBuildEnrollItgMessage(pMessageOut, pSizeOut, false, NULL, false, false, SearchTimeout, FaceBitStatus.RegisterStatus.AdmissionDirection);
      if (BuildMessageResults == true)
      {
        FaceUpdateEnrollmentDirection(FaceBitStatus.RegisterStatus.AdmissionDirection);
      }

      *pResponseTimeOut = (SearchTimeout + FACE_MESSAGE_TIME_BIAS) * 1000;
    }
    break;

    case FACE_GET_NUMBER_OF_TEMPLATE:
    {
      FaceBitStatus.EventStatus.MessageId = FACE_MESSAGE_REPLY;
      FaceBitStatus.EventStatus.CommandToSend = FACE_API_GET_ALL_USER_ID_CMD;

      BuildMessageResults = FaceBuildGetAllUserIdMessage(pMessageOut, pSizeOut);
      *pResponseTimeOut = FACE_MESSAGE_SENGING_RATED_TIME;
    }
    break;

    case FACE_INTO_POWER_DOWM:
    {
      FaceBitStatus.EventStatus.MessageId = FACE_MESSAGE_REPLY;
      FaceBitStatus.EventStatus.CommandToSend = FACE_API_POWER_DOWN_CMD;

      BuildMessageResults = FaceBuildModulePowerDownMessage(pMessageOut, pSizeOut);
      *pResponseTimeOut = FACE_MESSAGE_SENGING_RATED_TIME;
    }
    break;

    default:
    {
      FaceBitStatus.EventStatus.MessageId = FACE_MESSAGE_REPLY;
      FaceBitStatus.EventStatus.CommandToSend = FACE_API_GET_STATUS_CMD;
      FaceBitStatus.EventStatus.StepsOfSending = FACE_GET_MODULE_STATUS;

      BuildMessageResults = FaceBuildGetModuleStatusMessage(pMessageOut, pSizeOut);
      *pResponseTimeOut = FACE_MESSAGE_SENGING_RATED_TIME;
    }
    break;
    }
  }

  return BuildMessageResults;
}

bool FaceBuildUserAuthenticationMessage(uint8_t *pMessageOut, uint16_t *pSizeOut, uint32_t *pResponseTimeOut)
{
  bool BuildMessageResults = false;

  if ((pMessageOut != NULL) && (pSizeOut != NULL))
  {
    switch (FaceBitStatus.EventStatus.StepsOfSending)
    {
    case FACE_IDENTIFY_USER_PERMISSIONS:
    {
      uint8_t SearchTimeout = FaceGetSearchTimeout();
      FaceBitStatus.EventStatus.MessageId = FACE_MESSAGE_REPLY;
      FaceBitStatus.EventStatus.CommandToSend = FACE_API_VERIFY_CMD;

      BuildMessageResults = FaceBuildStartVerifyMessage(pMessageOut, pSizeOut, SearchTimeout);
      *pResponseTimeOut = (SearchTimeout + FACE_MESSAGE_TIME_BIAS) * 1000;
    }
    break;

    case FACE_INTO_POWER_DOWM:
    {
      FaceBitStatus.EventStatus.MessageId = FACE_MESSAGE_REPLY;
      FaceBitStatus.EventStatus.CommandToSend = FACE_API_POWER_DOWN_CMD;

      BuildMessageResults = FaceBuildModulePowerDownMessage(pMessageOut, pSizeOut);
      *pResponseTimeOut = FACE_MESSAGE_SENGING_RATED_TIME;
    }
    break;

    default:
    {
      FaceBitStatus.EventStatus.MessageId = FACE_MESSAGE_REPLY;
      FaceBitStatus.EventStatus.CommandToSend = FACE_API_GET_STATUS_CMD;
      FaceBitStatus.EventStatus.StepsOfSending = FACE_GET_MODULE_STATUS;

      BuildMessageResults = FaceBuildGetModuleStatusMessage(pMessageOut, pSizeOut);
      *pResponseTimeOut = FACE_MESSAGE_SENGING_RATED_TIME;
    }
    break;
    }
  }

  return BuildMessageResults;
}

bool FaceBuildDeletingSpecificUsersMessage(uint8_t *pMessageOut, uint16_t *pSizeOut, uint32_t *pResponseTimeOut)
{
  bool BuildMessageResults = false;

  if ((pMessageOut != NULL) && (pSizeOut != NULL))
  {
    switch (FaceBitStatus.EventStatus.StepsOfSending)
    {
    case FACE_DELETING_USERS:
    {
      FaceBitStatus.EventStatus.MessageId = FACE_MESSAGE_REPLY;
      FaceBitStatus.EventStatus.CommandToSend = FACE_API_DEL_USER_CMD;

      BuildMessageResults = FaceBuildExampleDeleteSpecifiedUserMessage(pMessageOut, pSizeOut, FaceBitStatus.DeleteUserInformation.UserId[FaceBitStatus.DeleteUserInformation.NumberOfDelete - 1]);
      *pResponseTimeOut = FACE_MESSAGE_SENGING_RATED_TIME;
    }
    break;

    case FACE_EXECUTE_FACTORY_RESET:
    {
      FaceBitStatus.EventStatus.MessageId = FACE_MESSAGE_REPLY;
      FaceBitStatus.EventStatus.CommandToSend = FACE_API_DEL_ALL_CMD;

      BuildMessageResults = FaceBuildDeleteAllUserMessage(pMessageOut, pSizeOut);
      *pResponseTimeOut = FACE_MESSAGE_SENGING_RATED_TIME;
    }
    break;

    case FACE_GET_NUMBER_OF_TEMPLATE:
    {
      FaceBitStatus.EventStatus.MessageId = FACE_MESSAGE_REPLY;
      FaceBitStatus.EventStatus.CommandToSend = FACE_API_GET_ALL_USER_ID_CMD;

      BuildMessageResults = FaceBuildGetAllUserIdMessage(pMessageOut, pSizeOut);
      *pResponseTimeOut = FACE_MESSAGE_SENGING_RATED_TIME;
    }
    break;

    case FACE_INTO_POWER_DOWM:
    {
      FaceBitStatus.EventStatus.MessageId = FACE_MESSAGE_REPLY;
      FaceBitStatus.EventStatus.CommandToSend = FACE_API_POWER_DOWN_CMD;

      BuildMessageResults = FaceBuildModulePowerDownMessage(pMessageOut, pSizeOut);
      *pResponseTimeOut = FACE_MESSAGE_SENGING_RATED_TIME;
    }
    break;

    default:
    {
      FaceBitStatus.EventStatus.MessageId = FACE_MESSAGE_REPLY;
      FaceBitStatus.EventStatus.CommandToSend = FACE_API_GET_STATUS_CMD;

      FaceBitStatus.EventStatus.StepsOfSending = FACE_GET_MODULE_STATUS;
      BuildMessageResults = FaceBuildGetModuleStatusMessage(pMessageOut, pSizeOut);
      *pResponseTimeOut = FACE_MESSAGE_SENGING_RATED_TIME;
    }
    break;
    }
  }

  return BuildMessageResults;
}

bool FaceBuildRegistrationByEigenvalueMessage(uint8_t *pMessageOut, uint16_t *pSizeOut, uint32_t *pResponseTimeOut)
{
  bool BuildMessageResults = false;

  if ((pMessageOut != NULL) && (pSizeOut != NULL))
  {
    switch (FaceBitStatus.EventStatus.StepsOfSending)
    {
    case FACE_TRANSMIT_FILE_PACKET:
    {
      uint8_t FileDataPacket[FACE_MAX_FILE_REQUEST_SIZE] = {0};

      FaceBitStatus.EventStatus.MessageId = FACE_MESSAGE_REPLY;
      FaceBitStatus.EventStatus.CommandToSend = FACE_API_TRANS_FILE_PACKET_CMD;

      FaceReadFeatureValueFilesForMemory(FaceBitStatus.FileOperation.RequestFileSize, FileDataPacket, FaceBitStatus.FileOperation.TransmitterSize);
      PRINT("[face]: file offset: %d, transmitter size: %d.\r\n", FaceBitStatus.FileOperation.RequestFileSize, FaceBitStatus.FileOperation.TransmitterSize);

      BuildMessageResults = FaceBuildTransFilePacketMessage(pMessageOut, pSizeOut, FaceBitStatus.FileOperation.FileSize, FaceBitStatus.FileOperation.RequestFileSize, FaceBitStatus.FileOperation.TransmitterSize, FileDataPacket);
      *pResponseTimeOut = FACE_MESSAGE_SENGING_RATED_TIME;
    }
    break;

    case FACE_TRANSMIT_FILE_END:
    {
      FaceBitStatus.EventStatus.MessageId = FACE_MESSAGE_REPLY;
      FaceBitStatus.EventStatus.CommandToSend = FACE_API_TRANS_FILE_PACKET_CMD;

      BuildMessageResults = FaceBuildTransFilePacketMessage(pMessageOut, pSizeOut, FaceBitStatus.FileOperation.FileSize, 0, 0, NULL);
    }
    break;

    case FACE_ENROLL_FROM_FILE:
    {
      FaceBitStatus.EventStatus.MessageId = FACE_MESSAGE_REPLY;
      FaceBitStatus.EventStatus.CommandToSend = FACE_API_ENROLL_WITH_FEATURE_CMD;

      BuildMessageResults = FaceBuildEnrollFromFeatureMessage(pMessageOut, pSizeOut, false, NULL, FACE_DIRECTION_MIDDLE, 255);
    }
    break;

    case FACE_GET_NUMBER_OF_TEMPLATE:
    {
      FaceBitStatus.EventStatus.MessageId = FACE_MESSAGE_REPLY;
      FaceBitStatus.EventStatus.CommandToSend = FACE_API_GET_ALL_USER_ID_CMD;

      BuildMessageResults = FaceBuildGetAllUserIdMessage(pMessageOut, pSizeOut);
    }
    break;

    case FACE_INTO_POWER_DOWM:
    {
      FaceBitStatus.EventStatus.MessageId = FACE_MESSAGE_REPLY;
      FaceBitStatus.EventStatus.CommandToSend = FACE_API_POWER_DOWN_CMD;

      BuildMessageResults = FaceBuildModulePowerDownMessage(pMessageOut, pSizeOut);
    }
    break;

    default:
    {
      FaceBitStatus.EventStatus.MessageId = FACE_MESSAGE_REPLY;
      FaceBitStatus.EventStatus.CommandToSend = FACE_API_GET_STATUS_CMD;
      FaceBitStatus.EventStatus.StepsOfSending = FACE_GET_MODULE_STATUS;

      BuildMessageResults = FaceBuildGetModuleStatusMessage(pMessageOut, pSizeOut);
    }
    break;
    }
  }

  return BuildMessageResults;
}

uint8_t FaceParsingSelfTestMessage(const void *pDataIn, uint16_t DataSize, uint8_t ParsingResult)
{
  bool ParsingState = false;
  uint8_t ParsingResults = FACE_EXECUTE_ERROR;
  uint8_t *pSelfTestMessage = (uint8_t *)pDataIn;

  if (pSelfTestMessage != NULL)
  {
    switch (FaceBitStatus.EventStatus.StepsOfSending)
    {
    case FACE_WAIT_READY:
    {
      uint8_t NotificationEventType = 0;

      if (ParsingResult == MR_SUCCESS)
      {
        ParsingState = FaceParesNotificationsMessage(pSelfTestMessage, &NotificationEventType);
        if (ParsingState == true)
        {
          ParsingResults = FACE_EXECUTE_ERROR;

          if (NotificationEventType == NID_READY)
          {
            ParsingResults = FACE_EXECUTE_SUCCESS;
            FaceBitStatus.EventStatus.StepsOfSending = FACE_GET_MODULE_STATUS;
          }
        }
      }
    }
    break;

    case FACE_GET_MODULE_STATUS:
    {
      if (ParsingResult == MR_SUCCESS)
      {
        uint8_t ModuleStatus = 0;

        ParsingState = FaceReplyGetModuleStatusMessage(pSelfTestMessage, &ModuleStatus);
        if (ParsingState == true)
        {
          ParsingResults = FACE_EXECUTE_RETRY;

          if (ModuleStatus == MODULE_IDLE)
          {
            ParsingResults = FACE_EXECUTE_SUCCESS;
            FaceBitStatus.EventStatus.StepsOfSending = (FacelGetDeviceActivationStatus() == true) ? FACE_GET_SERIAL_NUMBER : FACE_EXECUTE_FACTORY_RESET;
          }
        }
      }
    }
    break;

    case FACE_EXECUTE_FACTORY_RESET:
    {
      if (ParsingResult == MR_SUCCESS)
      {
        ParsingState = FaceReplyDeleteAllUserMessage(pSelfTestMessage);
        if (ParsingState == true)
        {
          ParsingResults = FACE_EXECUTE_SUCCESS;
          FaceBitStatus.EventStatus.StepsOfSending = FACE_GET_SERIAL_NUMBER;
        }
      }
    }
    break;

    case FACE_GET_SERIAL_NUMBER:
    {
      if (ParsingResult == MR_SUCCESS)
      {
        memset(FaceBitStatus.HardwareAttribute.SerialNumber, 0, FACE_MODULE_SN_LENGTH);

        ParsingState = FaceReplyGetModuleSnMessage(pSelfTestMessage, FaceBitStatus.HardwareAttribute.SerialNumber);
        if (ParsingState == true)
        {
          ParsingResults = FACE_EXECUTE_SUCCESS;
          FaceBitStatus.EventStatus.StepsOfSending = FACE_GET_APPLICATION_VERSION;
        }
      }
    }
    break;

    case FACE_GET_APPLICATION_VERSION:
    {
      if (ParsingResult == MR_SUCCESS)
      {
        memset(FaceBitStatus.HardwareAttribute.ApplicationVersion, 0, FACE_LENGTH_OF_VERSION_INFORMATION);

        ParsingState = FaceReplyGetAlgorithmVersionMessage(pSelfTestMessage, FaceBitStatus.HardwareAttribute.ApplicationVersion);
        if (ParsingState == true)
        {
          ParsingResults = FACE_EXECUTE_SUCCESS;
          FaceBitStatus.EventStatus.StepsOfSending = FACE_GET_ALGORITHM_VERSION;
        }
      }
    }
    break;

    case FACE_GET_ALGORITHM_VERSION:
    {
      if (ParsingResult == MR_SUCCESS)
      {
        memset(FaceBitStatus.HardwareAttribute.AlgorithmVersion, 0, FACE_LENGTH_OF_VERSION_INFORMATION);

        ParsingState = FaceReplyGetAlgorithmVersionMessage(pSelfTestMessage, FaceBitStatus.HardwareAttribute.AlgorithmVersion);
        if (ParsingState == true)
        {
          ParsingResults = FACE_EXECUTE_SUCCESS;
          FaceBitStatus.EventStatus.StepsOfSending = FACE_GET_NUMBER_OF_TEMPLATE;
        }
      }
    }
    break;

    case FACE_GET_NUMBER_OF_TEMPLATE:
    {
      if (ParsingResult == MR_SUCCESS)
      {
        FaceBitStatus.HardwareAttribute.NumberOfUser = 0;

        ParsingState = FaceReplyGetAllUserIdMessage(pSelfTestMessage, &FaceBitStatus.HardwareAttribute.NumberOfUser, NULL);
        if (ParsingState == true)
        {
          ParsingResults = FACE_EXECUTE_SUCCESS;
          FaceBitStatus.EventStatus.StepsOfSending = FACE_INTO_POWER_DOWM;
        }
      }
    }
    break;

    case FACE_INTO_POWER_DOWM:
    {
      ParsingState = FaceReplyModulePowerDownMessage(pSelfTestMessage);
      if (ParsingState == true)
      {
        ParsingResults = FACE_EXECUTE_OVER;
        FaceBitStatus.EventStatus.StepsOfSending = FACE_WAIT_READY;
      }
    }
    break;

    default:
      break;
    }
  }

  return ParsingResults;
}

uint8_t FaceParsingDeviceFactorySettingMessage(const void *pDataIn, uint16_t DataSize, uint8_t ParsingResult)
{
  bool ParsingState = false;
  uint8_t ParsingResults = FACE_EXECUTE_ERROR;
  uint8_t *pFactorySettingMessage = (uint8_t *)pDataIn;

  if (pFactorySettingMessage != NULL)
  {
    switch (FaceBitStatus.EventStatus.StepsOfSending)
    {
    case FACE_WAIT_READY:
    {
      if (ParsingResult == MR_SUCCESS)
      {
        uint8_t NotificationEventType = 0;

        ParsingState = FaceParesNotificationsMessage(pFactorySettingMessage, &NotificationEventType);
        if (ParsingState == true)
        {
          ParsingResults = FACE_EXECUTE_ERROR;

          if (NotificationEventType == NID_READY)
          {
            ParsingResults = FACE_EXECUTE_SUCCESS;
            FaceBitStatus.EventStatus.StepsOfSending = FACE_GET_MODULE_STATUS;
          }
        }
      }
    }
    break;

    case FACE_GET_MODULE_STATUS:
    {
      if (ParsingResult == MR_SUCCESS)
      {
        uint8_t ModuleStatus = 0;

        ParsingState = FaceReplyGetModuleStatusMessage(pFactorySettingMessage, &ModuleStatus);
        if (ParsingState == true)
        {
          ParsingResults = FACE_EXECUTE_RETRY;

          if (ModuleStatus == MODULE_IDLE)
          {
            ParsingResults = FACE_EXECUTE_SUCCESS;
            FaceBitStatus.EventStatus.StepsOfSending = FACE_EXECUTE_FACTORY_RESET;
          }
        }
      }
    }
    break;

    case FACE_EXECUTE_FACTORY_RESET:
    {
      if (ParsingResult == MR_SUCCESS)
      {
        ParsingState = FaceReplyDeleteAllUserMessage(pFactorySettingMessage);
        if (ParsingState == true)
        {
          ParsingResults = FACE_EXECUTE_SUCCESS;
          FaceBitStatus.EventStatus.StepsOfSending = FACE_GET_NUMBER_OF_TEMPLATE;
        }
      }
    }
    break;

    case FACE_GET_NUMBER_OF_TEMPLATE:
    {
      if (ParsingResult == MR_SUCCESS)
      {
        FaceBitStatus.HardwareAttribute.NumberOfUser = 0;

        ParsingState = FaceReplyGetAllUserIdMessage(pFactorySettingMessage, &FaceBitStatus.HardwareAttribute.NumberOfUser, NULL);
        if (ParsingState == true)
        {
          ParsingResults = FACE_EXECUTE_SUCCESS;
          FaceBitStatus.EventStatus.StepsOfSending = FACE_INTO_POWER_DOWM;
        }
      }
    }
    break;

    case FACE_INTO_POWER_DOWM:
    {
      ParsingState = FaceReplyModulePowerDownMessage(pFactorySettingMessage);
      if (ParsingState == true)
      {
        ParsingResults = FACE_EXECUTE_OVER;
        FaceBitStatus.EventStatus.StepsOfSending = FACE_WAIT_READY;
      }
    }
    break;

    default:
      break;
    }
  }

  return ParsingResults;
}

uint8_t FaceParsingForcedToGotoSleepMessage(const void *pDataIn, uint16_t DataSize, uint8_t ParsingResult)
{
  bool ParsingState = false;
  uint8_t ParsingResults = FACE_EXECUTE_ERROR;
  uint8_t *pForcedToGotoSleepMessage = (uint8_t *)pDataIn;

  if (pForcedToGotoSleepMessage != NULL)
  {
    switch (FaceBitStatus.EventStatus.StepsOfSending)
    {
    case FACE_INTO_STANDBY:
    {
      ParsingState = FaceReplySoftwareResetMessage(pForcedToGotoSleepMessage);
      if (ParsingState == true)
      {
        ParsingResults = FACE_EXECUTE_SUCCESS;
        FaceBitStatus.EventStatus.StepsOfSending = FACE_INTO_POWER_DOWM;
      }
    }
    break;

    case FACE_INTO_POWER_DOWM:
    {
      ParsingState = FaceReplyModulePowerDownMessage(pForcedToGotoSleepMessage);
      if (ParsingState == true)
      {
        ParsingResults = FACE_EXECUTE_OVER;
        FaceBitStatus.EventStatus.StepsOfSending = FACE_WAIT_READY;
      }
    }
    break;

    default:
      break;
    }
  }

  return ParsingResults;
}

uint8_t FaceParsingGetEigenvalueFileMessage(const void *pDataIn, uint16_t DataSize, uint8_t ParsingResult)
{
  bool ParsingState = false;
  uint8_t ParsingResults = FACE_EXECUTE_ERROR;
  uint8_t *pGetEigenvalueFileMessage = (uint8_t *)pDataIn;

  if (pGetEigenvalueFileMessage != NULL)
  {
    switch (FaceBitStatus.EventStatus.StepsOfSending)
    {
    case FACE_WAIT_READY:
    {
      if (ParsingResult == MR_SUCCESS)
      {
        uint8_t NotificationEventType = 0;

        ParsingState = FaceParesNotificationsMessage(pGetEigenvalueFileMessage, &NotificationEventType);
        if (ParsingState == true)
        {
          ParsingResults = FACE_EXECUTE_ERROR;

          if (NotificationEventType == NID_READY)
          {
            ParsingResults = FACE_EXECUTE_SUCCESS;
            FaceBitStatus.EventStatus.StepsOfSending = FACE_GET_MODULE_STATUS;
          }
        }
      }
    }
    break;

    case FACE_GET_MODULE_STATUS:
    {
      if (ParsingResult == MR_SUCCESS)
      {
        uint8_t ModuleStatus = 0;

        ParsingState = FaceReplyGetModuleStatusMessage(pGetEigenvalueFileMessage, &ModuleStatus);
        if (ParsingState == true)
        {
          ParsingResults = FACE_EXECUTE_RETRY;

          if (ModuleStatus == MODULE_IDLE)
          {
            ParsingResults = FACE_EXECUTE_SUCCESS;
            FaceBitStatus.EventStatus.StepsOfSending = FACE_EXECUTE_FACTORY_RESET;
          }
        }
      }
    }
    break;

    case FACE_GET_IMAGE_INFORMATION:
    {
      if (ParsingResult == MR_SUCCESS)
      {
        memset(&FaceBitStatus.FileOperation, 0, sizeof(FaceFileOperation_t));

        ParsingState = FaceReplyGetFeatureInformatizationMessage(pGetEigenvalueFileMessage, &FaceBitStatus.FileOperation.FileSize);
        if (ParsingState == true)
        {
          ParsingResults = FACE_EXECUTE_SUCCESS;
          FaceBitStatus.EventStatus.StepsOfSending = FACE_UPLOAD_IMAGE_DATA;

          FaceBitStatus.FileOperation.TransmitterSize = FACE_MAX_FILE_REQUEST_SIZE;
          if ((FaceBitStatus.FileOperation.FileSize - FaceBitStatus.FileOperation.RequestFileSize) < FACE_MAX_FILE_REQUEST_SIZE)
          {
            FaceBitStatus.FileOperation.TransmitterSize = (uint16_t)(FaceBitStatus.FileOperation.FileSize - FaceBitStatus.FileOperation.RequestFileSize);
          }
        }
      }
    }
    break;

    case FACE_UPLOAD_IMAGE_DATA:
    {
      if (ParsingResult == MR_SUCCESS)
      {
        ParsingState = FaceReplyUploadFeatureDataMessage(pGetEigenvalueFileMessage);
        if (ParsingState == true)
        {
          if (DataSize == FaceBitStatus.FileOperation.TransmitterSize)
          {
            if (FaceWriteFeatureValueFilesToMemory(FaceBitStatus.FileOperation.RequestFileSize, pGetEigenvalueFileMessage, FaceBitStatus.FileOperation.TransmitterSize) == true)
            {
              ParsingResults = FACE_EXECUTE_SUCCESS;

              FaceBitStatus.FileOperation.RequestFileSize += FaceBitStatus.FileOperation.TransmitterSize;
              if (FaceBitStatus.FileOperation.RequestFileSize < FaceBitStatus.FileOperation.FileSize)
              {
                FaceBitStatus.FileOperation.TransmitterSize = FACE_MAX_FILE_REQUEST_SIZE;
                if ((FaceBitStatus.FileOperation.FileSize - FaceBitStatus.FileOperation.RequestFileSize) < FACE_MAX_FILE_REQUEST_SIZE)
                {
                  FaceBitStatus.FileOperation.TransmitterSize = (uint16_t)(FaceBitStatus.FileOperation.FileSize - FaceBitStatus.FileOperation.RequestFileSize);
                }
              }
              else
              {
                FaceBitStatus.EventStatus.StepsOfSending = FACE_INTO_POWER_DOWM;
                FaceWriteEigenvalueFileInformation(FaceBitStatus.FileOperation.FileSize);
              }
            }
          }
        }
      }
    }
    break;

    case FACE_INTO_POWER_DOWM:
    {
      ParsingState = FaceReplyModulePowerDownMessage(pGetEigenvalueFileMessage);
      if (ParsingState == true)
      {
        ParsingResults = FACE_EXECUTE_OVER;
        FaceBitStatus.EventStatus.StepsOfSending = FACE_WAIT_READY;
      }
    }
    break;

    default:
      break;
    }
  }

  return ParsingResults;
}

uint8_t FaceParsingLocalRegisterUserMessage(const void *pDataIn, uint16_t DataSize, uint8_t ParsingResult)
{
  bool ParsingState = false;
  uint8_t ParsingResults = FACE_EXECUTE_ERROR;
  uint8_t *pLocalRegisterMessage = (uint8_t *)pDataIn;

  if (pLocalRegisterMessage != NULL)
  {
    FaceReloadLocalRegisterTimer();

    switch (FaceBitStatus.EventStatus.StepsOfSending)
    {
    case FACE_WAIT_READY:
    {
      if (ParsingResult == MR_SUCCESS)
      {
        uint8_t NotificationEventType = 0;

        ParsingState = FaceParesNotificationsMessage(pLocalRegisterMessage, &NotificationEventType);
        if (ParsingState == true)
        {
          ParsingResults = FACE_EXECUTE_ERROR;

          if (NotificationEventType == NID_READY)
          {
            ParsingResults = FACE_EXECUTE_SUCCESS;
            FaceBitStatus.EventStatus.StepsOfSending = FACE_GET_MODULE_STATUS;
          }
        }
      }
    }
    break;

    case FACE_GET_MODULE_STATUS:
    {
      if (ParsingResult == MR_SUCCESS)
      {
        uint8_t ModuleStatus = 0;

        ParsingState = FaceReplyGetModuleStatusMessage(pLocalRegisterMessage, &ModuleStatus);
        if (ParsingState == true)
        {
          ParsingResults = FACE_EXECUTE_RETRY;

          if (ModuleStatus == MODULE_IDLE)
          {
            ParsingResults = FACE_EXECUTE_SUCCESS;

            FaceBitStatus.RegisterStatus.UserId = FACE_VIRTUAL_USER;
            FaceBitStatus.EventStatus.StepsOfSending = FACE_USER_INTERACTIVE_REGISTRATION;
          }
        }
      }
    }
    break;

    case FACE_USER_INTERACTIVE_REGISTRATION:
    {
      if (ParsingResult == MR_SUCCESS)
      {
        uint8_t Direction = 0;

        ParsingState = FaceReplyEnrollItgMessage(pLocalRegisterMessage, &FaceBitStatus.RegisterStatus.UserId, &Direction);
        if (ParsingState == true)
        {
          if (Direction & FaceBitStatus.RegisterStatus.AdmissionDirection)
          {
            ParsingResults = FACE_EXECUTE_SUCCESS;

            if (FaceBitStatus.RegisterStatus.UserId != FACE_VIRTUAL_USER)
            {
              PRINT("[face]: register user success. new user id: %d.\r\n", FaceBitStatus.RegisterStatus.UserId);
              FaceBitStatus.EventStatus.StepsOfSending = FACE_GET_NUMBER_OF_TEMPLATE;
            }
          }
        }
      }
      else
      {
        switch (ParsingResult)
        {
        case MR_FAILED4_FACE_ENROLLED:
          ParsingResults = FACE_EXECUTE_USER_ALREADY_EXISTS;
          break;

        case MR_FAILED4_MAXUSER:
          ParsingResults = FACE_EXECUTE_USER_IS_FULL;
          break;

        default:
          ParsingResults = FACE_EXECUTE_ERROR;
          break;
        }
      }
    }
    break;

    case FACE_GET_NUMBER_OF_TEMPLATE:
    {
      FaceBitStatus.HardwareAttribute.NumberOfUser = 0;

      ParsingState = FaceReplyGetAllUserIdMessage(pLocalRegisterMessage, &FaceBitStatus.HardwareAttribute.NumberOfUser, NULL);
      if (ParsingState == true)
      {
        ParsingResults = FACE_EXECUTE_SUCCESS;
        FaceBitStatus.EventStatus.StepsOfSending = FACE_INTO_POWER_DOWM;
      }
    }
    break;

    case FACE_INTO_POWER_DOWM:
    {
      ParsingState = FaceReplyModulePowerDownMessage(pLocalRegisterMessage);
      if (ParsingState == true)
      {
        ParsingResults = FACE_EXECUTE_OVER;
        FaceBitStatus.EventStatus.StepsOfSending = FACE_WAIT_READY;
      }
    }
    break;

    default:
      break;
    }
  }

  return ParsingResults;
}

uint8_t FaceParsingUserAuthenticationMessage(const void *pDataIn, uint16_t DataSize, uint8_t ParsingResult)
{
  bool ParsingState = false;
  uint8_t ParsingResults = FACE_EXECUTE_ERROR;
  uint8_t *pAuthenticationMessage = (uint8_t *)pDataIn;

  if (pAuthenticationMessage != NULL)
  {
    switch (FaceBitStatus.EventStatus.StepsOfSending)
    {
    case FACE_WAIT_READY:
    {
      if (ParsingResult == MR_SUCCESS)
      {
        uint8_t NotificationEventType = 0;

        ParsingState = FaceParesNotificationsMessage(pAuthenticationMessage, &NotificationEventType);
        if (ParsingState == true)
        {
          ParsingResults = FACE_EXECUTE_ERROR;

          if (NotificationEventType == NID_READY)
          {
            ParsingResults = FACE_EXECUTE_SUCCESS;
            FaceBitStatus.EventStatus.StepsOfSending = FACE_GET_MODULE_STATUS;
          }
        }
      }
    }
    break;

    case FACE_GET_MODULE_STATUS:
    {
      if (ParsingResult == MR_SUCCESS)
      {
        uint8_t ModuleStatus = 0;

        ParsingState = FaceReplyGetModuleStatusMessage(pAuthenticationMessage, &ModuleStatus);
        if (ParsingState == true)
        {
          ParsingResults = FACE_EXECUTE_RETRY;

          if (ModuleStatus == MODULE_IDLE)
          {
            ParsingResults = FACE_EXECUTE_SUCCESS;
            FaceBitStatus.EventStatus.StepsOfSending = FACE_IDENTIFY_USER_PERMISSIONS;
          }
        }
      }
    }
    break;

    case FACE_IDENTIFY_USER_PERMISSIONS:
    {
      if (ParsingResult == MR_SUCCESS)
      {
        ParsingState = FaceReplyVerifyMessage(pAuthenticationMessage, &FaceBitStatus.EventStatus.TempUserId, NULL, NULL, NULL);
        if (ParsingState == true)
        {
          PRINT("[face]: successful authentication. user id: %d.\r\n", FaceBitStatus.EventStatus.TempUserId);

          ParsingResults = FACE_EXECUTE_SUCCESS;
          FaceBitStatus.EventStatus.StepsOfSending = FACE_INTO_POWER_DOWM;
        }
      }
      else
      {
        ParsingResults = FACE_EXECUTE_ERROR;
      }
    }
    break;

    case FACE_INTO_POWER_DOWM:
    {
      ParsingState = FaceReplyModulePowerDownMessage(pAuthenticationMessage);
      if (ParsingState == true)
      {
        ParsingResults = FACE_EXECUTE_OVER;
        FaceBitStatus.EventStatus.StepsOfSending = FACE_WAIT_READY;
      }
    }
    break;

    default:
      break;
    }
  }

  return ParsingResults;
}

uint8_t FaceParsingDeletingSpecificUsersMessage(const void *pDataIn, uint16_t DataSize, uint8_t ParsingResult)
{
  bool ParsingState = false;
  uint8_t ParsingResults = FACE_EXECUTE_ERROR;
  uint8_t *pDeletingSpecificUsersMessage = (uint8_t *)pDataIn;

  if (pDeletingSpecificUsersMessage != NULL)
  {
    switch (FaceBitStatus.EventStatus.StepsOfSending)
    {
    case FACE_WAIT_READY:
    {
      if (ParsingResult == MR_SUCCESS)
      {
        uint8_t NotificationEventType = 0;

        ParsingState = FaceParesNotificationsMessage(pDeletingSpecificUsersMessage, &NotificationEventType);
        if (ParsingState == true)
        {
          ParsingResults = FACE_EXECUTE_ERROR;

          if (NotificationEventType == NID_READY)
          {
            ParsingResults = FACE_EXECUTE_SUCCESS;
            FaceBitStatus.EventStatus.StepsOfSending = FACE_GET_MODULE_STATUS;
          }
        }
      }
    }
    break;

    case FACE_GET_MODULE_STATUS:
    {
      if (ParsingResult == MR_SUCCESS)
      {
        uint8_t ModuleStatus = 0;

        ParsingState = FaceReplyGetModuleStatusMessage(pDeletingSpecificUsersMessage, &ModuleStatus);
        if (ParsingState == true)
        {
          ParsingResults = FACE_EXECUTE_RETRY;

          if (ModuleStatus == MODULE_IDLE)
          {
            ParsingResults = FACE_EXECUTE_SUCCESS;
            FaceBitStatus.EventStatus.StepsOfSending = (FaceBitStatus.DeleteUserInformation.NumberOfDelete != FACE_DELETE_ALL_USER_IDENT) ? FACE_DELETING_USERS : FACE_EXECUTE_FACTORY_RESET;
          }
        }
      }
    }
    break;

    case FACE_DELETING_USERS:
    {
      if (ParsingResult == MR_SUCCESS)
      {
        ParsingState = FaceReplyExampleDeleteSpecifiedUserMessage(pDeletingSpecificUsersMessage);
        if (ParsingState == true)
        {
          ParsingResults = FACE_EXECUTE_SUCCESS;

          FaceBitStatus.DeleteUserInformation.NumberOfDelete--;
          if (FaceBitStatus.DeleteUserInformation.NumberOfDelete == 0)
          {
            FaceBitStatus.EventStatus.StepsOfSending = FACE_GET_NUMBER_OF_TEMPLATE;
          }
        }
      }
    }
    break;

    case FACE_EXECUTE_FACTORY_RESET:
    {
      if (ParsingResult == MR_SUCCESS)
      {
        ParsingState = FaceReplyDeleteAllUserMessage(pDeletingSpecificUsersMessage);
        if (ParsingState == true)
        {
          ParsingResults = FACE_EXECUTE_SUCCESS;
          FaceBitStatus.EventStatus.StepsOfSending = FACE_GET_NUMBER_OF_TEMPLATE;
        }
      }
    }
    break;

    case FACE_GET_NUMBER_OF_TEMPLATE:
    {
      if (ParsingResult == MR_SUCCESS)
      {
        FaceBitStatus.HardwareAttribute.NumberOfUser = 0;

        ParsingState = FaceReplyGetAllUserIdMessage(pDeletingSpecificUsersMessage, &FaceBitStatus.HardwareAttribute.NumberOfUser, NULL);
        if (ParsingState == true)
        {
          ParsingResults = FACE_EXECUTE_SUCCESS;
          FaceBitStatus.EventStatus.StepsOfSending = FACE_INTO_POWER_DOWM;
        }
      }
    }
    break;

    case FACE_INTO_POWER_DOWM:
    {
      memset(&FaceBitStatus.DeleteUserInformation, 0, sizeof(FaceDeleteUserInformation_t));

      ParsingState = FaceReplyModulePowerDownMessage(pDeletingSpecificUsersMessage);
      if (ParsingState == true)
      {
        ParsingResults = FACE_EXECUTE_OVER;
        FaceBitStatus.EventStatus.StepsOfSending = FACE_WAIT_READY;
      }
    }
    break;

    default:
      break;
    }
  }

  return ParsingResults;
}

uint8_t FaceParsingRegistrationByEigenvalueMessage(const void *pDataIn, uint16_t DataSize, uint8_t ParsingResult)
{
  bool ParsingState = false;
  uint8_t ParsingResults = FACE_EXECUTE_ERROR;
  uint8_t *pRegistrationMessage = (uint8_t *)pDataIn;

  if (pRegistrationMessage != NULL)
  {
    switch (FaceBitStatus.EventStatus.StepsOfSending)
    {
    case FACE_WAIT_READY:
    {
      if (ParsingResult == MR_SUCCESS)
      {
        uint8_t NotificationEventType = 0;

        ParsingState = FaceParesNotificationsMessage(pRegistrationMessage, &NotificationEventType);
        if (ParsingState == true)
        {
          ParsingResults = FACE_EXECUTE_ERROR;

          if (NotificationEventType == NID_READY)
          {
            ParsingResults = FACE_EXECUTE_SUCCESS;
            FaceBitStatus.EventStatus.StepsOfSending = FACE_GET_MODULE_STATUS;
          }
        }
      }
    }
    break;

    case FACE_GET_MODULE_STATUS:
    {
      if (ParsingResult == MR_SUCCESS)
      {
        uint8_t ModuleStatus = 0;

        ParsingState = FaceReplyGetModuleStatusMessage(pRegistrationMessage, &ModuleStatus);
        if (ParsingState == true)
        {
          ParsingResults = FACE_EXECUTE_RETRY;

          if (ModuleStatus == MODULE_IDLE)
          {
            ParsingResults = FACE_EXECUTE_ERROR;
            memset(&FaceBitStatus.FileOperation, 0, sizeof(FaceFileOperation_t));

            FaceReadEigenvalueFileInformation(&FaceBitStatus.FileOperation.FileSize);
            if ((FaceBitStatus.FileOperation.FileSize > 0) && (FaceBitStatus.FileOperation.FileSize <= FACE_MAX_OF_EIGENVALUE_FILE_SIZE))
            {
              ParsingResults = FACE_EXECUTE_SUCCESS;
              FaceBitStatus.EventStatus.StepsOfSending = FACE_TRANSMIT_FILE_PACKET;

              FaceBitStatus.FileOperation.TransmitterSize = FACE_MAX_FILE_REQUEST_SIZE;
              if ((FaceBitStatus.FileOperation.FileSize - FaceBitStatus.FileOperation.RequestFileSize) < FACE_MAX_FILE_REQUEST_SIZE)
              {
                FaceBitStatus.FileOperation.TransmitterSize = (uint16_t)(FaceBitStatus.FileOperation.FileSize - FaceBitStatus.FileOperation.RequestFileSize);
              }
            }
          }
        }
      }
    }
    break;

    case FACE_TRANSMIT_FILE_PACKET:
    {
      if (ParsingResult == MR_SUCCESS)
      {
        ParsingState = FaceReplyTransFilePacketMessage(pRegistrationMessage);
        if (ParsingState == true)
        {
          ParsingResults = FACE_EXECUTE_SUCCESS;

          FaceBitStatus.FileOperation.RequestFileSize += FaceBitStatus.FileOperation.TransmitterSize;
          if (FaceBitStatus.FileOperation.RequestFileSize < FaceBitStatus.FileOperation.FileSize)
          {
            FaceBitStatus.FileOperation.TransmitterSize = FACE_MAX_FILE_REQUEST_SIZE;
            if ((FaceBitStatus.FileOperation.FileSize - FaceBitStatus.FileOperation.RequestFileSize) < FACE_MAX_FILE_REQUEST_SIZE)
            {
              FaceBitStatus.FileOperation.TransmitterSize = (uint16_t)(FaceBitStatus.FileOperation.FileSize - FaceBitStatus.FileOperation.RequestFileSize);
            }
          }
          else
          {
            FaceBitStatus.EventStatus.StepsOfSending = FACE_TRANSMIT_FILE_END;
          }
        }
      }
    }
    break;

    case FACE_TRANSMIT_FILE_END:
    {
      if (ParsingResult == MR_SUCCESS)
      {
        ParsingState = FaceReplyTransFilePacketMessage(pRegistrationMessage);
        if (ParsingState == true)
        {
          ParsingResults = FACE_EXECUTE_SUCCESS;
          FaceBitStatus.EventStatus.StepsOfSending = FACE_ENROLL_FROM_FILE;
        }
      }
    }
    break;

    case FACE_ENROLL_FROM_FILE:
    {
      if (ParsingResult == MR_SUCCESS)
      {
        uint8_t Direction = 0;

        ParsingState = FaceReplyEnrollFromFeatureMessage(pRegistrationMessage, &FaceBitStatus.RegisterStatus.UserId, &Direction);
        if (ParsingState == true)
        {
          ParsingResults = FACE_EXECUTE_ERROR;

          if (FaceBitStatus.RegisterStatus.UserId != FACE_VIRTUAL_USER)
          {
            PRINT("[face]: register user success. new user id: %d.\r\n", FaceBitStatus.RegisterStatus.UserId);

            ParsingResults = FACE_EXECUTE_SUCCESS;
            FaceBitStatus.EventStatus.StepsOfSending = FACE_GET_NUMBER_OF_TEMPLATE;
          }
        }
      }
      else
      {
        switch (ParsingResult)
        {
        case MR_FAILED4_FACE_ENROLLED:
          ParsingResults = FACE_EXECUTE_USER_ALREADY_EXISTS;
          break;

        case MR_FAILED4_MAXUSER:
          ParsingResults = FACE_EXECUTE_USER_IS_FULL;
          break;

        default:
          ParsingResults = FACE_EXECUTE_ERROR;
          break;
        }
      }
    }
    break;

    case FACE_GET_NUMBER_OF_TEMPLATE:
    {
      if (ParsingResult == MR_SUCCESS)
      {
        FaceBitStatus.HardwareAttribute.NumberOfUser = 0;

        ParsingState = FaceReplyGetAllUserIdMessage(pRegistrationMessage, &FaceBitStatus.HardwareAttribute.NumberOfUser, NULL);
        if (ParsingState == true)
        {
          ParsingResults = FACE_EXECUTE_SUCCESS;
          FaceBitStatus.EventStatus.StepsOfSending = FACE_INTO_POWER_DOWM;
        }
      }
    }
    break;

    case FACE_INTO_POWER_DOWM:
    {
      ParsingState = FaceReplyModulePowerDownMessage(pRegistrationMessage);
      if (ParsingState == true)
      {
        ParsingResults = FACE_EXECUTE_OVER;
        FaceBitStatus.EventStatus.StepsOfSending = FACE_WAIT_READY;
      }
    }
    break;

    default:
      break;
    }
  }

  return ParsingResults;
}

bool FaceVerifyMessageValidity(uint8_t *pMessageIn, uint8_t *pDataOffsetOut, uint16_t *pDataSizeOut, uint8_t *pResultOut)
{
  uint16_t SizeOfPacket = 0;
  bool VerificationResults = false;
  FaceProtocolFormat_t *pFaceProtocol = (FaceProtocolFormat_t *)pMessageIn;

  if ((pFaceProtocol != NULL) && (pDataOffsetOut != NULL) && (pDataSizeOut != NULL) && (pResultOut != NULL))
  {
    if ((pFaceProtocol->SyncCode[0] == FACE_SYNCWORD_H_BYTE) && (pFaceProtocol->SyncCode[1] == FACE_SYNCWORD_L_BYTE))
    {
      SizeOfPacket = (pFaceProtocol->DataLenght[0] << 8) | pFaceProtocol->DataLenght[1];

      uint8_t CheckCode = FaceParityCheck(&pFaceProtocol->MessageId, SizeOfPacket + 3);
      if (CheckCode == pFaceProtocol->Data[SizeOfPacket])
      {
        if (pFaceProtocol->MessageId == FaceBitStatus.EventStatus.MessageId)
        {
          switch (pFaceProtocol->MessageId)
          {
          case FACE_MESSAGE_REPLY:
          {
            FaceReplyProtocolFormat_t *pReplyProtocolFormat = (FaceReplyProtocolFormat_t *)pFaceProtocol->Data;

            if (pReplyProtocolFormat->Command == FaceBitStatus.EventStatus.CommandToSend)
            {
              VerificationResults = true;
              *pResultOut = pReplyProtocolFormat->Result;

              memcpy(pDataOffsetOut, pReplyProtocolFormat->Data, SizeOfPacket - 2);
            }
          }
          break;

          case FACE_MESSAGE_NOTE:
          case FACE_MESSAGE_IMAGE:
          {
            VerificationResults = true;
            memcpy(pDataOffsetOut, pFaceProtocol->Data, SizeOfPacket);
          }
          break;
          }
        }
      }
    }

    *pDataSizeOut = SizeOfPacket;
  }

  return VerificationResults;
}

void FaceFunctionalInitialization(void)
{
  memset(&FaceBitStatus.EventStatus, 0, sizeof(FaceEventStatus_t));
  FaceBitStatus.EventStatus.MessageId = FACE_MESSAGE_NOTE;
}

void FaceStartForcedToGotoSleep(void)
{
  memset(&FaceBitStatus.EventStatus, 0, sizeof(FaceEventStatus_t));
}

void FaceStartLocalRegisterTasks(uint8_t WaitTime)
{
  memset(&FaceBitStatus.FileOperation, 0, sizeof(FaceFileOperation_t));
  memset(&FaceBitStatus.RegisterStatus, 0, sizeof(FaceRegisterStatus_t));

  FacePreparationsBeforeLocalRegister(WaitTime);
}

void FaceStartUserAuthenticationTasks(void)
{
  FaceUpdateTheEnrollmentDirectionToFront();
}

void FaceMarkUserToGetEigenvalueFile(uint16_t UserId)
{
  memset(&FaceBitStatus.FileOperation, 0, sizeof(FaceFileOperation_t));
  memset(&FaceBitStatus.RegisterStatus, 0, sizeof(FaceRegisterStatus_t));

  FaceBitStatus.EventStatus.TempUserId = UserId;
}

void FaceStartDeleteUserTasks(void)
{
  memset(&FaceBitStatus.DeleteUserInformation, 0, sizeof(FaceDeleteUserInformation_t));
}

void FaceRecordUsersToBeDeleted(uint16_t UserId)
{
  if (UserId != FACE_DELETE_ALL_USER_IDENT)
  {
    if (FaceBitStatus.DeleteUserInformation.NumberOfDelete < FACE_NUMBER_OF_REGISTERED_USERS)
    {
      FaceBitStatus.DeleteUserInformation.UserId[FaceBitStatus.DeleteUserInformation.NumberOfDelete++] = UserId;
    }
  }
  else
  {
    FaceBitStatus.DeleteUserInformation.NumberOfDelete = FACE_DELETE_ALL_USER_IDENT;
  }
}

uint16_t FaceGetLocalRegisterUserId(void)
{
  return FaceBitStatus.RegisterStatus.UserId;
}

uint16_t FaceGetAuthorizedUserCode(void)
{
  return FaceBitStatus.EventStatus.TempUserId;
}

#endif
